package io.kiki.sba.registry.server.metadata.resource;

import io.kiki.sba.registry.common.model.CollectionSdks;
import io.kiki.sba.registry.common.model.GenericResponse;
import io.kiki.sba.registry.common.model.Response;
import io.kiki.sba.registry.common.model.Tuple;
import io.kiki.sba.registry.common.model.console.CircuitBreakerData;
import io.kiki.sba.registry.common.model.console.CircuitBreakerData.CircuitBreakOption;
import io.kiki.sba.registry.common.model.console.PersistenceData;
import io.kiki.sba.registry.common.model.console.PersistenceDataBuilder;
import io.kiki.sba.registry.common.model.constants.ValueConstants;
import io.kiki.sba.registry.server.metadata.provide.data.ProvideDataService;
import io.kiki.sba.registry.server.metadata.resource.filter.LeaderAwareRestController;
import io.kiki.sba.registry.store.api.DBResponse;
import io.kiki.sba.registry.store.api.OperationStatus;
import io.kiki.sba.registry.util.JsonUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Resource;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;


@Path("circuit/breaker")
@LeaderAwareRestController
public class CircuitBreakerResources {

    private static final Logger logger = LoggerFactory.getLogger(CircuitBreakerResources.class);

    @Resource
    private ProvideDataService provideDataService;

    @GET
    @Path("query")
    @Produces(MediaType.APPLICATION_JSON)
    public GenericResponse<CircuitBreakerData> query() {
        Tuple<CircuitBreakerData, Long> tuple = queryData();
        return new GenericResponse().fillSucceed(tuple.o1);
    }

    @POST
    @Path("switch/close")
    @Produces(MediaType.APPLICATION_JSON)
    public Response switchClose() {

        boolean put = switchSave(false);

        logger.info("circuit breaker switch close ret: {}", put);
        Response response = Response.buildSuccessResponse();
        response.setSuccess(put);
        return response;
    }

    @POST
    @Path("switch/open")
    @Produces(MediaType.APPLICATION_JSON)
    public Response switchOpen() {

        boolean put = switchSave(true);

        logger.info("circuit breaker switch close ret: {}", put);
        Response response = Response.buildSuccessResponse();
        response.setSuccess(put);
        return response;
    }

    @POST
    @Path("add")
    @Produces(MediaType.APPLICATION_JSON)
    public Response add(@FormParam("option") String option, @FormParam("ips") String ips) {
        CircuitBreakOption optionEnum = CircuitBreakOption.getByOption(option);
        if (optionEnum == null || StringUtils.isBlank(ips)) {
            logger.error("circuit breaker option or ips is blank.");
            return Response.buildFailedResponse("option or ips is blank.");
        }

        Tuple<CircuitBreakerData, Long> tuple = queryData();
        tuple.o1.add(optionEnum, CollectionSdks.toIpSet(ips));

        PersistenceData persistenceData = PersistenceDataBuilder.createPersistenceData(ValueConstants.CIRCUIT_BREAKER_DATA_ID, JsonUtils.writeValueAsString(tuple.o1));
        boolean put = provideDataService.saveProvideData(persistenceData, tuple.o2);

        logger.info("add circuit breaker ips: {}, ret: {}", ips, put);
        Response response = Response.buildSuccessResponse();
        response.setSuccess(put);
        return response;
    }

    @POST
    @Path("remove")
    @Produces(MediaType.APPLICATION_JSON)
    public Response remove(@FormParam("option") String option, @FormParam("ips") String ips) {
        CircuitBreakOption optionEnum = CircuitBreakOption.getByOption(option);

        if (optionEnum == null || StringUtils.isBlank(ips)) {
            logger.error("circuit breaker option or ips is blank.");
            return Response.buildFailedResponse("option or ips is blank.");
        }
        Tuple<CircuitBreakerData, Long> tuple = queryData();
        tuple.o1.remove(optionEnum, CollectionSdks.toIpSet(ips));

        PersistenceData persistenceData = PersistenceDataBuilder.createPersistenceData(ValueConstants.CIRCUIT_BREAKER_DATA_ID, JsonUtils.writeValueAsString(tuple.o1));
        boolean put = provideDataService.saveProvideData(persistenceData, tuple.o2);

        logger.info("remove circuit breaker ips: {}, ret: {}", ips, put);
        Response response = Response.buildSuccessResponse();
        response.setSuccess(put);
        return response;
    }

    private boolean switchSave(boolean b) {
        Tuple<CircuitBreakerData, Long> tuple = queryData();
        tuple.o1.setAddressSwitch(b);

        PersistenceData persistenceData = PersistenceDataBuilder.createPersistenceData(ValueConstants.CIRCUIT_BREAKER_DATA_ID, JsonUtils.writeValueAsString(tuple.o1));
        return provideDataService.saveProvideData(persistenceData, tuple.o2);
    }

    private Tuple<CircuitBreakerData, Long> queryData() {
        DBResponse<PersistenceData> queryResponse = provideDataService.queryProvideData(ValueConstants.CIRCUIT_BREAKER_DATA_ID);
        long expectVersion = 0;
        PersistenceData persistenceData = queryResponse.getEntity();
        CircuitBreakerData read = null;
        if (queryResponse.getOperationStatus() == OperationStatus.success && persistenceData != null) {
            read = JsonUtils.read(persistenceData.getData(), CircuitBreakerData.class);
            expectVersion = persistenceData.getVersion();
        }
        if (read == null) {
            read = new CircuitBreakerData();
        }
        return new Tuple<>(read, expectVersion);
    }
}
